/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package cz.worktracker.controller;

import cz.worktracker.enums.DataSetsEnum;
import cz.worktracker.model.entities.Customer;
import cz.worktracker.model.entities.Taskinterval;
import cz.worktracker.model.entities.Project;
import cz.worktracker.model.entities.Task;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level;
import javax.annotation.ManagedBean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.SessionScoped;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.inject.Inject;
import javax.inject.Named;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Transaction;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

/**
 * TaskManager
 * Vytvoření nového projektu
 * @since 2010-04-23
 * @author kyjovsky
 */

@ManagedBean
@SessionScoped
@Named
public class TaskManager extends AbstractManager
                            implements Serializable {

        private static final long serialVersionUID = 1L;

        private static final String NAV_EDIT = "/user/task/edit";
        private static final String NAV_DETAIL = "/user/task/detail";
        private static final String NAV_REDIRECT = "?faces-redirect=true";

        private Task task;
        private Long timerMsec;
        private Long timerTotalMsec;
        private boolean isTimerStart;
        private Integer timerTask;
        private Integer idActTask;
        private String intervalNote;


        /* TABULKA */
        private AbstractPaginator paginator;
        private DataModel dataModel;
        private DataSetsEnum DSEnum;
        private int rowsPerPage = DSEnum.ITEMS_PER_PAGE_DEFAULT.getValue();

        private String searchPattern = "";

        private String sortByField = DSEnum.SORT_BY_FIELD.getStringValue();
        private String sortDirection = DSEnum.SORT_DIRECTION.getStringValue();
        /* TABULKA */

        @Inject UserManager userManager;
        @Inject ProjectManager projectManager;

        @PostConstruct
        public void construct() {
            init();
        }

        @PreDestroy
        public void destroy() {
            task = null;
            paginator = null;
            dataModel = null;
        }


        private void init() {
            if( task == null ) {
                task = new Task();
                task.setIdProject(-1);
            }
            this.setTimerMsec(0L);
            this.setTimerTask(null);
            this.setIsTimerStart(true);
            this.setTimerTotalMsec(0L);
        }


        public boolean getNewTask() {
            task = null;
            init();
            return true;
        }


        public String create() {
            if (task != null) {
                try {
                    if(task.getOverheadCost() == null) task.setOverheadCost(new Float (0.0));
                    task.setIdProject(projectManager.getProject().getId());
                    Transaction tx = getSession().beginTransaction();
                    getSession().save(task);
                    tx.commit();
                    init();
                } catch (Exception e) {
                    getLogger(getClass()).log(Level.SEVERE, "Error on try to save Task: " + getTask(), e);
                    addMessage("Error on try to save Task", FacesMessage.SEVERITY_ERROR);
                    return null;
                }
            }
            return "/user/project/detail" + NAV_REDIRECT;
        }

    /**
     * Method sets current user record for editation.
     * @return
     */
    public String edit() {
        task = (Task) getList().getRowData();

        return NAV_EDIT + NAV_REDIRECT;
    }


        public String update() {
            if (task != null) {
                try {
                    if(task.getOverheadCost() == null) task.setOverheadCost(new Float (0.0));
                    Transaction tx = getSession().beginTransaction();
                    getSession().update(task);
                    tx.commit();
                    task = null;
                    init();
                } catch (Exception e) {
                    getLogger(getClass()).log(Level.SEVERE, "Error on try to save Task: " + getTask(), e);
                    addMessage("Error on try to save Task", FacesMessage.SEVERITY_ERROR);
                    return null;
                }
            }
            return "/user/project/detail" + NAV_REDIRECT;
        }


        public Task getTask() {
            return task;
        }

        public void setTask(Task task) {
            this.task = task;
        }
        

        /**
         * Prepares dataModel.
        * @return Hell I really want to know.
        */
        public String prepareDataModel() {
            resetDataModel();
            return NAV_DETAIL + NAV_REDIRECT;
         }


        /**
         * Method nulls reference of dataModel.
        */
        public void resetDataModel() {
            dataModel = null;
        }


        /**
        * Method nulls reference of paginator.
        */
        public void resetPagination() {
            paginator = null;
        }


        /**
        * Returns page switcher and override abstract methods from AbstractPaginator.
        * @return Paginator object.
        */
        public AbstractPaginator getPaginator() {
            if( paginator == null ) {
                paginator = new AbstractPaginator( rowsPerPage ) {

               /*
                * While creating a new instance we have to implement abstract
                * methods defined in AbstractPaginator class.
                */

                @Override
                public int getItemsCount() {
                    return getProjectTasksCount();
                }

                @Override
                public DataModel createPageDataModel() {
                    ListDataModel list = null;

                    try {
                        Transaction tx = getSession().beginTransaction();
                        Criteria ct = getSession().createCriteria(Task.class);
                        ct.add( Restrictions.eq( "idProject", projectManager.getProject().getId() ) );

                        if( getSearchPattern().length() > 0 ) {
                            ct.add( Restrictions.like( "name" , getSearchPattern() , MatchMode.ANYWHERE ) );
                            ct.add( Restrictions.like( "note" , getSearchPattern() , MatchMode.ANYWHERE ) );
                        }

                        if( getSortDirection().equalsIgnoreCase( "asc" ) ) {
                            ct.addOrder( Order.asc( getSortByField()) );
                        } else {
                            ct.addOrder( Order.desc( getSortByField()) );
                        }

                        ct.setFirstResult(getPageFirstItem());
                        ct.setMaxResults(getPageSize());
                        list = new ListDataModel(ct.list());
                        tx.commit();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    return list;
                    }
                };
            }
            return paginator;
        }


       /**
        * Returns count of records returned to view.
        * @return int
        */
        public int getRowsPerPage() {
            return rowsPerPage;
        }


        /**
         * Sets count of records returned to view.
         * @param rowsPerPage
         */
        public void setRowsPerPage( int rowsPerPage ) {
            this.rowsPerPage = rowsPerPage;

            resetDataModel();
            resetPagination();
        }

        /**
         * Returns DataModel for dataTable.
         * @return DataModel for dataTable.
        */
        public DataModel getList() {
            if( dataModel == null ) {
                dataModel = getPaginator().createPageDataModel();
            }

            return dataModel;
        }


        /**
        * Next page.
        */
        public void next() {
            getPaginator().nextPage();
            resetDataModel();
        }

        /**
        * Last page.
        */
        public void last() {
            getPaginator().lastPage();
            resetDataModel();
        }


        /**
        * Previous page.
        */
        public void previous() {
            getPaginator().previousPage();
            resetDataModel();
        }

        /**
        * First page.
        */
        public void first() {
            getPaginator().firstPage();
            resetDataModel();
        }


        /**
        * Increments count of items per page.
        */
        public void more() {
            setRowsPerPage(getRowsPerPage() + DSEnum.ITEMS_PER_PAGE_INCREMENT.getValue());

            resetPagination();
            resetDataModel();
        }


        /**
        * * Decrements count of items per page.
        */
        public void less() {
            setRowsPerPage(getRowsPerPage() - DSEnum.ITEMS_PER_PAGE_INCREMENT.getValue());

            resetPagination();
            resetDataModel();
        }


        /**
        * Retrieves sort params through context and initiates sort.
        */
        public void sort() {
            /**
            * Try to gain params send by <f:param />
            */
            FacesContext context = FacesContext.getCurrentInstance();
            Map requestMap = context.getExternalContext().getRequestParameterMap();
            setSortByField( (String) requestMap.get("by") );
            setSortDirection( (String) requestMap.get("order") );

            resetPagination();
            resetDataModel();

        }


        /**
        * Returns projects count.
        * @return int means projects count.
        */
        public int getProjectTasksCount() {
            Transaction tx = getSession().beginTransaction();
            String hql = "select count(*) from Task as task where task.idProject = '" + projectManager.getProject().getId() + "'";
            int count = ( (Long) (getSession().createQuery(hql).iterate().next()) ).intValue();
            tx.commit();
            return count;
        }


        /**
        * Returns field name in JPA entity according which sorting will be provided.
        * @return String
        */
        public String getSortByField() {
            return sortByField;
        }


        /**
        * Sets field name in JPA entity according which sorting will be provided.
        * @param sortByField
        */
        public void setSortByField(String sortByField) {
            this.sortByField = sortByField;
        }


        /**
        * Returns sort direction (ascending: asc; descending desc).
        * @return String
        */
        public String getSortDirection() {
            return sortDirection;
        }


        /**
        * Sets sort direction (ascending: asc; descending desc).
        * @param sortDirection
        */
        public void setSortDirection(String sortDirection) {
            this.sortDirection = sortDirection;
        }


        /**
        * Returns searched string.
        * @return String
        */
        public String getSearchPattern() {
            return searchPattern;
        }


        /**
        * Sets searched string.
        * @param searchPattern
        */
        public void setSearchPattern(String searchPattern) {
            this.searchPattern = searchPattern;
        }


        public boolean getTimer() {
            int id_task = ((Task) getList().getRowData()).getId();

            ListDataModel list = null;

            try {
                Transaction tx = getSession().beginTransaction();
                Criteria ct = getSession().createCriteria(Taskinterval.class);
                ct.add( Restrictions.eq( "idTask", id_task ) );

                list = new ListDataModel(ct.list());
                tx.commit();
            } catch (Exception e) {
                  e.printStackTrace();
            }

            setIsTimerStart (false);
            Taskinterval interval;
            long diff = 0;
            setTimerMsec(0L);
            for (int i = 0; i < list.getRowCount(); i++) {
                list.setRowIndex(i);
                interval = (Taskinterval) list.getRowData();
                if (interval.getStopTime() == null) {
                    setTimerMsec((new Date()).getTime() - interval.getStartTime().getTime());
                    diff += getTimerMsec();
                    setIsTimerStart (true);
                }
                else {
                    diff += interval.getStopTime().getTime() - interval.getStartTime().getTime();
                    setIsTimerStart(false);
                }

             }

            setTimerTotalMsec(diff);
            setTimerTask (id_task);

            return true;
        }

        public String getStartTimer() {
            Taskinterval newInterval = new Taskinterval();

            task = (Task) getList().getRowData();

            newInterval.setIdTask(task.getId());
            newInterval.setStartTime(new Date());

            try {
                 Transaction tx = getSession().beginTransaction();
                 getSession().save(newInterval);
                 tx.commit();
                 init();
             } catch (Exception e) {
                 getLogger(getClass()).log(Level.SEVERE, "Error on try to save Interval: " + newInterval, e);
                 addMessage("Error on try to save Interval", FacesMessage.SEVERITY_ERROR);
                 return null;
             }

            return null;
        }


        public void saveRow() {
            idActTask = ((Task) getList().getRowData()).getId();
            intervalNote = "";
        }


        public String stopTimer() {
            int taskId = idActTask;
            System.out.println("TASK:" + taskId);
            try {
                Transaction tx = getSession().beginTransaction();
                Criteria ct = getSession().createCriteria(Taskinterval.class);
                ct.add( Restrictions.eq( "idTask", taskId ) );
                ct.add( Restrictions.isNull("stopTime") );
                System.out.println("DB:" + ct.list().size());
                Taskinterval newInterval = (Taskinterval) ct.list().get(0);

                newInterval.setStopTime(new Date());
                newInterval.setNote(intervalNote);
                
                tx.commit();
            } catch (Exception e) {
                  e.printStackTrace();
            }

            return null;
        }

    public boolean isIsTimerStart() {
        return isTimerStart;
    }

    public void setIsTimerStart(boolean isTimerStart) {
        this.isTimerStart = isTimerStart;
    }

    public Long getTimerMsec() {
        return timerMsec;
    }

    public void setTimerMsec(Long timerMsec) {
        this.timerMsec = timerMsec;
    }

    public Integer getTimerTask() {
        return timerTask;
    }

    public void setTimerTask(Integer timerTask) {
        this.timerTask = timerTask;
    }

    public Long getTimerTotalMsec() {
        return timerTotalMsec;
    }

    public void setTimerTotalMsec(Long timerTotalMsec) {
        this.timerTotalMsec = timerTotalMsec;
    }


    public String detail() {

       task = (Task) getList().getRowData();
       resetDataModel();
       return NAV_DETAIL + NAV_REDIRECT;
   }

    /**
     * Based on actual row, method returns Customer name
     * @return String
     */
    public String getProjectName() {

        int idProject = task.getIdProject();

        if( idProject > 0 ) {
            Project tmpProject = getProjectById( idProject );
            return tmpProject.getName();
        }
        
        return null;
    }

    /**
     * Method returns Project by his id.
     * @param id Project ID
     * @return Project
     */
    public Project getProjectById(int id) {
        Transaction tx = getSession().beginTransaction();
        String hql = "from Project as project where project.id = '"+ id +"'";
        Query query = getSession().createQuery( hql );
        query.setMaxResults( 1 );
        Project project =  (Project) query.uniqueResult();
        tx.commit();
        return project;
    }

    public String getIntervalNote() {
        return intervalNote;
    }

    public void setIntervalNote(String intervalNote) {
        this.intervalNote = intervalNote;
    }


    /**
    * Returns task ids of current user.
    */
    public ArrayList<Integer> getTaskIds() {

       ArrayList<Integer> projectIds = projectManager.getProjectIds();
       ArrayList<Integer> result = new ArrayList<Integer>();

        try {
            Transaction tx = getSession().beginTransaction();
            Criteria ct = getSession().createCriteria(Task.class);
            ct.add( Restrictions.in( "idProject", projectIds.toArray() ) );
            Iterator it = ct.list().iterator();

            while( it.hasNext() ) {
                Task tmpTask = (Task) it.next();
                result.add( tmpTask.getId() );
            }
            tx.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }


    public Task getTaskById( int id ) {
        Transaction tx = getSession().beginTransaction();
        String hql = "from Task as task where task.id = '"+ id +"'";
        Query query = getSession().createQuery( hql );
        query.setMaxResults( 1 );
        task =  (Task) query.uniqueResult();
        tx.commit();
        return task;
    }


    /**
     * Returns true. Always!
     * @return boolean
     */
    public boolean getTrue() {
        return true;
    }

}
